热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

不同点|都会_RPCRPC入门了解&最简单的RPC的实现

篇首语:本文由编程笔记#小编为大家整理,主要介绍了RPC----RPC入门了解&最简单的RPC的实现相关的知识,希望对你有一定的参考价值。RPC入门了

篇首语:本文由编程笔记#小编为大家整理,主要介绍了RPC ---- RPC入门了解 & 最简单的RPC的实现相关的知识,希望对你有一定的参考价值。



RPC入门了解


  • 一、历史背景
  • 二、理论知识
    • 1、概念
    • 2、为什么要用RPC
    • 3、工作原理
    • 4、RPC解决了什么问题?
    • 5、RPC vs HTTP 远程调用方式
    • 6、常用RPC框架

  • 三、实现
    • 1、对象序列化
      • 1.1 序列化的原因
      • 1.2 概念
      • 1.3 解决方案(RPC序列化框架)
      • 1.4 代码实现

    • 2、网络通讯协议
      • 2.1 基于TCP协议实现的RPC
        • 2.1.1 版本一
          • 2.1.1.1 原理
          • 2.1.1.2 场景
          • 2.1.1.3 实现代码
          • 2.1.1.4 缺陷

        • 2.1.2 版本二
          • 2.1.2.1 原理
          • 2.1.2.2 场景
          • 2.1.2.3 实现代码
          • 2.1.2.4 缺陷

        • 2.1.3 总结

      • 2.2 基于HTTP协议实现的RPC
        • 2.2.1 HTTP协议
        • 2.2.2 设计一个简单应用层协议(Servlet)
          • 工具类ProtocolUtil
          • 客户端实现
          • 服务端实现

        • 2.2.3 通过HttpClient发送HTTP请求
          • 2.2.3.1 使用原因
          • 2.2.3.2 代码


      • 2.3 TCP协议 vs HTTP协议 实现的RPC




一、历史背景
  • 从单机走向分布式,产生了很多分布式的通信方式


    • 最古老也是最有效的,并且永不过时的,TCP/UDP的二进制传。事实上所有通信方式归根到底都是TCP/UDP

    • CORBA(Common Object Reqeust Broker Architecute),古老而复杂的,支持面向对象的通信协议

    • Web Service (SOA SOAP RDDI WSDL)

      基于http + xml的标准化Web API

    • RestFul (Representational State Transfer)

      回归简单化本源的Web API的事实标准

      http://www.baidu.com/people/zhangsan

      http + json

    • RMI(Remote Method Invocation)

      Java内部的分布式通信协议

    • JMS(Java Message Service)

      JavaEE中的消息框架标准,为很多MQ所支持

    • RPC(Remote Procedure Call)

      远程方法调用,重点在于方法调用(不支持对象的概念),具体实现甚至可以用RMI、RestFul等去实现,但一般不用,因为RMI不能跨语言,而RestFul效率太低。多用于服务器集群间的通信,因此常使用更加高效、短小精悍的传输模式以提高效率


二、理论知识

1、概念



RPC(Remote Procedure Call),远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。


通俗点:


  • 就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据

2、为什么要用RPC


  • 可以做到分布式,现代化的微服务
  • 部署灵活
  • 解耦服务
  • 扩展性强

RPC的目的是让你在本地调用远程的方法,而对你来说这个 调用是透明的,你并不知道这个调用的方法是部署哪里。通过RPC能解耦服务,这才是使用RPC的真正目的。

单台服务器处理能力有限,RPC可提升系统处理能力和吞吐量,也是实现分布式计算的基础。


3、工作原理

RPC采用 客户机/服务器模式

请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续执行。

远程调用过程:


  1. 调用客户端句柄:执行传送参数
  2. 调用本地系统内核发送网络消息
  3. 消息传送到远程主机
  4. 服务器句柄得到消息并取得消息
  5. 执行远程过程
  6. 执行的过程将结果返回服务器句柄
  7. 服务器句柄返回结果,调用远程系统内核
  8. 消息传回本地主机
  9. 客户句柄向内核接收消息
  10. 客户接收句柄返回的数据

4、RPC解决了什么问题?


  • 通讯问题

    即A与B之间的通信,建立TCP连接

  • 寻址问题

    A通过RPC框架连接到B的服务器及特定端口和调用的方法名

  • 参数序列化与反序列化

    发起远程调用参数值需要二进制化,服务器收到二进制参数需要反序列化


5、RPC vs HTTP 远程调用方式

常见的远程调用方式有以下几种:

RPC服务



自定义数据格式,基于原生TCP通信,速度快,效率高。


RPC的框架:webservie(cxf)、dubbo


HTTP服务



http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。现在客户端浏览器与服务端通信基本都是采用Http协议。也可以用来进行远程服务调用。缺点是消息封装臃肿


现在热门的Rest风格,就可以通过http协议来实现。


http的实现技术:HttpClient


两者比较


  • 相同点:底层通讯都是基于socket,都可以实现远程调用,都可以实现服务调用服务。

  • 不同点:


    • RPC


      • 框架有:dubbo、cxf、(RMI远程方法调用)Hessian

      • 当使用RPC框架实现服务间调用的时候,要求服务提供方和服务消费方 都必须使用统一的RPC框架,要么都dubbo,要么都cxf。

      • 跨操作系统同一编程语言内使用

      • 优势:调用快、处理快

    • HTTP


      • 框架有:httpClient

      • 当使用http进行服务间调用的时候,无需关注服务提供方使用的编程语言,也无需关注服务消费方使用的编程语言,服务提供方只需要提供restful风格的接口,服务消费方,按照restful的原则,请求服务即可

      • 跨系统跨编程语言的远程调用框架

      • 优势:通用性强

补充:


  • 从传输速度上来看,因为HTTP封装的数据量更多所以数据传输量更大,所以RPC的传输速度是比RESTFUL更快的。

  • 因为HTTP协议是各个框架都普遍支持的。


    • 在不知道情况来源的框架、数据形势是什么样的,所以在网关可以使用Restful利用http来接受。

    • 而在微服务内部的各模块之间因为各协议方案是公司内部自己定的,所以知道各种数据方式,可以使用TCP传输以使各模块之间的数据传输更快。

    • 所以可以网关和外界的数据传输使用RESTFUL,微服务内部的各模块之间使用RPC。

  • RESTFUL的API的设计上是面向资源的,对于同一资源的获取、传输、修改可以使用GET、POST、PUT来对同一个URL进行区别,而RPC通常把动词直接体现在URL上

从图上可以看出,二者其实都可以看出在进行实现RPC的时候,底层的通信协议是可以使用HTTP协议的,另外单独的使用HTTP协议也是可以直接的实现调用的功能,理论上,HTTP的请求也是一种方法的调用,通过get或者post方法和url去调用方法,但是HTTP为了更高的可读性将请求头变得非常的臃肿,传输效率比较低,而RPC则是牺牲了可读性使得效率更高。

换句话说其实二者是一种功能,只不过应用的场景不同,而且针对点不同,HTTP是针对Client和Server ;而 RPC是针对 Server 与Server之间的调用,另外RPC之间的调用效率更加的高,而且增加了ZK进行服务的自动配置与管理。

换句话说,上层的协议还是都是依赖于TCP/IP协议,总的来说就是基于字节流来进行编码。


6、常用RPC框架


  • Dubbo

    Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案

  • gRPC

    是Google开发的高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言,本身它不是分布式的,所以要实现上面的框架的功能需要进一步的开发。


三、实现

实现RPC主要是做到两点:


  • 实现远程调用其它计算机的服务


    • 要实现远程调用,就需要通过网络传输数据。A程序提供服务,B程序通过网络请求参数传递给A,A本地执行后得到结果,再将结果返回给B程序。


      • 何种网络通信协议?

        现在比较流行的RPC框架,都会采用TCP协议作为底层传输协议。

        RPC通讯协议:http、http2.0(gRPC)、TCP(同步/异步;阻塞/非阻塞)、WebService。

      • 数据传输格式?

        两个程序进行通讯,必须约定好数据传输格式,即定义好

        请求和响应格式,另外,数据在网络中传输需要进行序列化,所以还需要约定统一的序列化的方式

  • 像调用本地服务一样调用远程服务


    • 如果仅仅是远程调用,还不算是RCP,因为RPC强调的是过程调用,调用的过程对用户而言应该是透明的,用户不应该关心调用的细节,可以像调用本地服务一样调用远程服务。所以RPC一定要对调用的过程进行封装

调用流程图


1、对象序列化


1.1 序列化的原因

任何形式的数据都需要转换成二进制流在网络传输


1.2 概念


  • 对象序列化

    将对象转换为二进制流的过程

  • 对象反序列化

    将二进制流恢复为对象的过程


1.3 解决方案(RPC序列化框架)


  • Google的Protocol Buffers

  • Java内置的序列化方式 java.io.Serializable

  • Hessian

  • json序列化框架


    • Jackson
    • google Gson
    • Ali FastJson
  • kyro

  • xmlrpc (xstream)


1.4 代码实现

public class JdkSerializable
public static void main(String[] args) throws IOException, ClassNotFoundException
User user = new User("zhangsan", 12);
byte[] bytes = serializableObject(user);
User newUser = (User) deSerializableObject(bytes);
System.out.println(newUser);

public static byte[] serializableObject(Object obj) throws IOException
User user = (User)obj;
// 定义一个字节数组输出流 (作用:获取内存中的缓存数据并转化为数组)
ByteArrayOutputStream os = new ByteArrayOutputStream();
// 对象输出流
// 构造方法,传递字节输出流
ObjectOutputStream out = new ObjectOutputStream(os);
// 将对象写入到字节数组输出,进行序列化
out.writeObject(user);
byte[] zhangsanByte = os.toByteArray();
return zhangsanByte;

public static Object deSerializableObject(byte[] bytes) throws IOException, ClassNotFoundException
// 字节数组输入流
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
// 从流中获取对象
ObjectInputStream in = new ObjectInputStream(is);
return in.readObject();



2、网络通讯协议


2.1 基于TCP协议实现的RPC


2.1.1 版本一

通过Socket编程,实现网络间的二进制字节数组(ByteArray)传输


2.1.1.1 原理

  • 基于Java的反射机制和Socket API实现

  • 方法的调用使用反射机制,消费者把需要调用的接口名称方法参数通过Socket通信传到服务端,服务端再通过反射机制调用对应的方法获取到值,然后再通过相同方式把结果返回给消费者


2.1.1.2 场景

服务消费者调用服务提供者的SayHelloService接口的sayHello(String helloArg)方法具体实现获取结果


2.1.1.3 实现代码

  • 服务提供者

    /**
    * @ClassName: Server
    * @Author: whc
    * @Date: 2021/05/22/0:52
    *
    * 阻塞式I/O,实际生产环境中出于性能的考虑,往往使用非阻塞I/O,以提供更大的吞吐量
    */

    public class Server
    private static HashMap<String, Class> registerTable &#61; new HashMap<>();
    static
    // key类型是接口,value是具体实现类
    registerTable.put(SayHelloService.class.getName(), SayHelloServiceImpl.class);

    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException
    ServerSocket server &#61; new ServerSocket(8080);
    while(true)
    Socket socket &#61; server.accept();
    // 读取服务信息
    ObjectInputStream input &#61; new ObjectInputStream(socket.getInputStream());
    String interfacename &#61; input.readUTF(); // 接口名称
    String methodName &#61; input.readUTF(); // 方法名称
    Class<?>[] parameterTypes &#61; (Class<?>[]) input.readObject(); // 参数类型
    Object[] arguments &#61; (Object[])input.readObject(); // 参数对象
    // 执行调用
    Class serviceinterfaceclass &#61; Class.forName(interfacename); // 得到接口的class
    Object service &#61; registerTable.get(interfacename).newInstance();//取得服务实现的对象
    Method method &#61; serviceinterfaceclass.getMethod(methodName, parameterTypes); // 获得要调用的方法
    Object result &#61; method.invoke(service, arguments);
    ObjectOutputStream output &#61; new ObjectOutputStream(socket.getOutputStream());
    output.writeObject(result);



  • 服务消费者

    /**
    * &#64;ClassName: Consumer 服务消费者
    * &#64;Author: whc
    * &#64;Date: 2021/05/22/0:43
    */

    public class Consumer
    public static void main(String[] args) throws NoSuchMethodException, IOException, ClassNotFoundException
    // 接口名称
    String interfacename &#61; SayHelloService.class.getName();
    // 需要远程执行的方法
    Method method &#61; SayHelloService.class.getMethod("sayHello", String.class);
    // 需要传递到远端的参数
    Object[] arguments &#61; "hello";
    Socket socket &#61; new Socket("127.0.0.1", 8080);
    // 将方法名称和参数传递到远端
    ObjectOutputStream output &#61; new ObjectOutputStream(socket.getOutputStream());
    output.writeUTF(interfacename); // 接口名称
    output.writeUTF(method.getName()); // 方法名称
    output.writeObject(method.getParameterTypes()); // 参数类型
    output.writeObject(arguments); // 参数
    // 从远端读取方法执行结果
    ObjectInputStream input &#61; new ObjectInputStream(socket.getInputStream());
    Object result &#61; input.readObject();
    System.out.println(result);



2.1.1.4 缺陷

  • 问题一

    版本一是一个最简单的RPC思想的例子&#xff0c;客户端要实现一堆通信的逻辑&#xff0c;耦合度太高&#xff0c;能不能客户端只负责调用接口&#xff0c;中间的网络细节不用去实现呢&#xff1f;接下来的版本二中的红色stub就是干这活的。

  • 问题二

    版本一只有SayHelloService一个接口的方法调用&#xff0c;假如Client端要调用的Server端接口有很多个呢&#xff1f;

    在版本一中可以通过反射机制&#xff0c;将Socket把要调用的接口名传给Server端&#xff0c;Server端再通过接口名反射去调用已实现的接口方法&#xff0c;但是这种实现方式&#xff1b;

    版本二则用动态代理&#xff0c;将Client要调用的接口名称传递给stub动态代理生成一个Client要调用的接口类。

    动态代理能解决繁琐编程


2.1.2 版本二

&#xff08;标准的RPC在Client和Server都需要有stub&#xff0c;为了一步一步理解RPC&#xff0c;所以版本二只在Client端加stub&#xff09;


2.1.2.1 原理

  • Client把调用Server端的具体细节交给了stub类&#xff0c;stub动态代理生成一个Client要调用的接口类&#xff0c;通过这个类去实现跟Server端的交互&#xff0c;让Client端实现只负责接口方法的调用&#xff0c;不用去关心一堆网络细节。
  • 当消费者调用服务接口的方法时&#xff0c;实际上调用的是接口代理类InvocationHandlerinvoke方法&#xff0c;把需要调用的接口名称、方法、参数通过代理类封装后传到服务端&#xff0c;服务端接收到信息后&#xff0c;找到对应的接口实现类&#xff0c;调用对应的方法获取到值&#xff0c;然后把结果返回给消费者。

2.1.2.2 场景

服务消费者传递对应的接口名称&#xff0c;调用对应接口的方法具体实现获取结果。

比如IUserService接口的方法findUserById&#xff0c;根据传入的id查找对应的用户

比如IProductService接口的方法findProductByName&#xff0c;根据传入的name查找对应的产品


2.1.2.3 实现代码

  • 服务提供者

    public class Server
    private static boolean running &#61; true;
    private static HashMap<String, Class> registerTable &#61; new HashMap<>();
    static
    // key类型是接口,value是具体实现类
    registerTable.put(IUserService.class.getName(), IUserServiceImpl.class);
    registerTable.put(IProductService.class.getName(), IProductServiceImpl.class);

    public static void main(String[] args) throws Exception
    ServerSocket server &#61; new ServerSocket(8080);
    while(running)
    Socket client &#61; server.accept();
    process(client);
    client.close();

    server.close();

    public static void process(Socket socket) throws Exception
    ObjectInputStream ois &#61; new ObjectInputStream(socket.getInputStream());
    ObjectOutputStream oos &#61; new ObjectOutputStream(socket.getOutputStream());
    //为了适应客户端通用化而做的改动
    String className &#61; ois.readUTF();
    String methodName &#61; ois.readUTF();
    Class[] parameterTypes &#61; (Class[]) ois.readObject();
    Object[] parameters &#61; (Object[]) ois.readObject();
    // IUserService service &#61; new IUserServiceImpl();//服务类型暂时还是写死的&#xff0c;不够灵活
    Object service &#61; registerTable.get(className).newInstance();
    //考虑到Client端可能调用Server端的多个方法,不仅仅是一个方法的情况
    //这时可以根据方法名和参数类型获取Method对象供后面反射调用接口实现类的方法
    Method method &#61; service.getClass().getMethod(methodName, parameterTypes);
    // 反射调用方法查询出结果
    Object o &#61; method.invoke(service, parameters);
    oos.writeObject(o);
    // flush() 是清空,而不是刷新
    oos.flush();


  • 服务消费者

    public class Client
    public static void main(String[] args) throws IOException
    // Client这里不用关注一堆网络交互的细节,直接调用Stub产生的代理对象的方法,既可完成整个链路的调用
    IUserService service &#61; (IUserService)Stub.getStub(IUserService.class);
    IProductService service1 &#61; (IProductService)Stub.getStub(IProductService.class);
    System.out.println(service.findUserById(123));
    System.out.println(service1.findProductByName("Bob"));


  • Stub

    在RPC里面是代理的意思&#xff0c;是个约定俗称的东西&#xff0c;所以不叫Proxy

    /**
    * &#64;ClassName: Stub 服务类型能够改变,变成通用的,主要是将服务类型作为参数传入getStub
    * &#64;Author: whc
    * &#64;Date: 2021/05/21/16:37
    */

    public class Stub
    public static Object getStub(Class c)
    InvocationHandler h &#61; new InvocationHandler()
    &#64;Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    Socket socket &#61; new Socket("127.0.0.1",8080);
    ObjectOutputStream oos &#61; new ObjectOutputStream(socket.getOutputStream());
    // 通用化的改变
    oos.writeUTF(c.getName()); // 服务类型
    oos.writeUTF(method.getName()); // 方法名字
    oos.writeObject(method.getParameterTypes()); // 方法参数类型
    oos.writeObject(args); // 参数
    oos.flush();
    // 接收服务端返回的结果,object读入
    ObjectInputStream ois &#61; new ObjectInputStream(socket.getInputStream());
    Object o &#61; ois.readObject();
    return o; // 返回通用对象

    ;
    // 动态代理产生一个实现了c接口的代理对象
    // 参数1是类加载器,参数2传入被代理的接口类,参数3是InvocationHandler:被代理时反射调用的方法,也就是Stub给Client端处理的一堆细节
    Object o &#61; Proxy.newProxyInstance(c.getClassLoader(), new Class[]c, h);
    System.out.println(o.getClass().getName());
    System.out.println(o.getClass().getInterfaces()[0]);
    // 返回实现接口类的代理对象
    return o;



2.1.2.4 缺陷

  • 问题一&#xff1a;在调用过程中&#xff0c;对象里面的所有字段细节&#xff0c;万一增减字段呢&#xff1f;
  • 问题二&#xff1a;Server端逻辑依旧很复杂&#xff0c;能不能做到像Client一样也通过Stub去处理细节问题呢&#xff1f;

2.1.3 总结

真实环境中&#xff0c;多个客户端多个请求到服务端&#xff0c;服务端需要同时接收和处理多个客户端请求&#xff0c;涉及并发处理、服务路由、负载均衡等问题&#xff0c;以上代码无法满足


2.2 基于HTTP协议实现的RPC



优点:


  • 简单、实用、开发方便

缺点:


  • 性能不是很稳定&#xff0c;在海量数据时&#xff0c;完全顶不住&#xff0c;容易宕机
  • 因为不是走的注册中心&#xff0c;不便于维护、监控以及统计分析


2.2.1 HTTP协议


  • Hypertext Transfer Protocol的缩写(超文本传输协议)
  • 属于应用层协议&#xff0c;构建在TCP与IP协议之上&#xff0c;处于TCP/IP体系架构顶端
  • 无需处理丢包补发、握手及数据的分段和重新组装等细节

2.2.2 设计一个简单应用层协议&#xff08;Servlet&#xff09;

原理


  1. 设计一个工具类ProtocolUtil&#xff0c;提供readRequest、readResponse、writeRequest、writeResponse方法

  2. 协议请求Request&#xff08;包括编码、命令和命令长度三个字段&#xff09;

  3. 协议响应Response&#xff08;包括编码、响应内容和响应内容长度三个字段&#xff09;

  4. 服务端和客户端

    客户端向服务端发送一条命令&#xff0c;服务端收到命令后&#xff0c;会判断命令是否为"HELLO"&#xff0c;如果是"HELLO"&#xff0c;则返回给客户端的响应为"hello!"&#xff0c;否则返回给客户端的响应为"bye bye!"。


工具类ProtocolUtil

  • readRequest(InputStream input)方法 &#xff1a; 协议请求Request : 包括编码、命令和命令长度三个字段
  • readResponse(InputStream input)方法&#xff1a;协议响应Response: 包括编码、长度和内容三个字段
  • writeRequest(OutputStream output, Request request)方法&#xff1a;将Request对象中的字段根据对应的编码写入输入流中
  • writeResponse(OutputStream output, Response response)方法&#xff1a;将Response对象中的字段根据对应的编码写入输入流中

public class ProtocolUtil
/**
* 协议请求Request : 包括编码、命令和命令长度三个字段
* readRequest方法将从传递进来的输入流中读取请求的编码、命令和长度三个参数&#xff0c;
* 进行相应的编码转换&#xff0c;并构造成Request对象返回
* &#64;param input
* &#64;return
*/

public static Request readRequest(InputStream input)
Request request &#61; new Request();
try
// 读取编码
byte[] encodeByte &#61; new byte[1];
input.read(encodeByte);
byte encode &#61; encodeByte[0];
// 读取命令长度
byte[] commandLengthBytes &#61; new byte[4]; // 缓冲区
input.read(commandLengthBytes);
// 将字节数组转化为整数
int commandLength &#61; ByteUtil.bytes2Int(commandLengthBytes);
// 读取命令
byte[] commandBytes &#61; new byte[commandLength];
input.read(commandBytes);
String command var cpro_id = "u6885494";

推荐阅读
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • REST与RPC:选择哪种API架构风格?
    在探讨REST与RPC这两种API架构风格的选择时,本文首先介绍了RPC(远程过程调用)的概念。RPC允许客户端通过网络调用远程服务器上的函数或方法,从而实现分布式系统的功能调用。相比之下,REST(Representational State Transfer)则基于资源的交互模型,通过HTTP协议进行数据传输和操作。本文将详细分析两种架构风格的特点、适用场景及其优缺点,帮助开发者根据具体需求做出合适的选择。 ... [详细]
  • 如果程序使用Go语言编写并涉及单向或双向TLS认证,可能会遭受CPU拒绝服务攻击(DoS)。本文深入分析了CVE-2018-16875漏洞,探讨其成因、影响及防范措施,为开发者提供全面的安全指导。 ... [详细]
  • 本文总结了一些开发中常见的问题及其解决方案,包括特性过滤器的使用、NuGet程序集版本冲突、线程存储、溢出检查、ThreadPool的最大线程数设置、Redis使用中的问题以及Task.Result和Task.GetAwaiter().GetResult()的区别。 ... [详细]
  • DVWA学习笔记系列:深入理解CSRF攻击机制
    DVWA学习笔记系列:深入理解CSRF攻击机制 ... [详细]
  • 小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限
    小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限 ... [详细]
  • 本文深入探讨了Spring Cloud Eureka在企业级应用中的高级使用场景及优化策略。首先,介绍了Eureka的安全配置,确保服务注册与发现过程的安全性。接着,分析了Eureka的健康检查机制,提高系统的稳定性和可靠性。随后,详细讨论了Eureka的各项参数调优技巧,以提升性能和响应速度。最后,阐述了如何实现Eureka的高可用性部署,保障服务的连续性和可用性。通过这些内容,开发者可以更好地理解和运用Eureka,提升微服务架构的整体效能。 ... [详细]
  • 最详尽的4K技术科普
    什么是4K?4K是一个分辨率的范畴,即40962160的像素分辨率,一般用于专业设备居多,目前家庭用的设备,如 ... [详细]
  • php更新数据库字段的函数是,php更新数据库字段的函数是 ... [详细]
  • 本文深入解析了通过JDBC实现ActiveMQ消息持久化的机制。JDBC能够将消息可靠地存储在多种关系型数据库中,如MySQL、SQL Server、Oracle和DB2等。采用JDBC持久化方式时,数据库会自动生成三个关键表:`activemq_msgs`、`activemq_lock`和`activemq_ACKS`,分别用于存储消息数据、锁定信息和确认状态。这种机制不仅提高了消息的可靠性,还增强了系统的可扩展性和容错能力。 ... [详细]
  • 在Java Web服务开发中,Apache CXF 和 Axis2 是两个广泛使用的框架。CXF 由于其与 Spring 框架的无缝集成能力,以及更简便的部署方式,成为了许多开发者的首选。本文将详细介绍如何使用 CXF 框架进行 Web 服务的开发,包括环境搭建、服务发布和客户端调用等关键步骤,为开发者提供一个全面的实践指南。 ... [详细]
  • TCP三次握手过程详解与图示解析
    本文详细解析了TCP三次握手的过程,并通过图示清晰展示了各个状态的变化。同时,文章还介绍了四次挥手的图解,解释了在TIME_WAIT状态中,客户端最后一次发送的ACK包的作用和重要性。 ... [详细]
  • C#中实现高效UDP数据传输技术
    C#中实现高效UDP数据传输技术 ... [详细]
  • PyQt5 QTextEdit:深入解析Python中多功能GUI库的应用与实现
    本文详细探讨了 PyQt5 中 QTextEdit 组件在 Python 多功能 GUI 库中的应用与实现。PyQt5 是 Qt 框架的 Python 绑定,提供了超过 620 个类和 6000 个函数及方法,广泛应用于跨平台应用程序开发。QTextEdit 作为其中的重要组件,支持丰富的文本编辑功能,如富文本格式、文本高亮和自定义样式等。PyQt5 的流行性不仅在于其强大的功能,还在于其易用性和灵活性,使其成为开发复杂用户界面的理想选择。 ... [详细]
author-avatar
刘刘刘刘
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有